#include "Application.h"

#include "glad/glad.h"

#include "GLFW/glfw3.h"
#include <iostream>

// 初始化Application的静态变量
Application *Application::mInstance = nullptr;

Application *Application::getInstance() {
  // 如果mInstance已经实例化，则直接返回；否则先new出来，再返回
  if (mInstance == nullptr) {
    mInstance = new Application();
  }
  return mInstance;
}

void Application::frameBufferSizeCallback(GLFWwindow *window, int width,
                                          int height) {
  std::cout << "resize hello world!" << std::endl;
  Application *self = (Application *)glfwGetWindowUserPointer(window);
  if (self->mResizeCallback != nullptr) {
    self->mResizeCallback(width, height);
  }
}

void Application::keyCallback(GLFWwindow *window, int key, int scancode,
                              int action, int mods) {
  // std::cout << "keyCallback" << std::endl;
  Application *self = (Application *)glfwGetWindowUserPointer(window);
  if (self->mKeyOperationCallback != nullptr) {
    self->mKeyOperationCallback(key, action, mods);
  }
}

Application::Application() {}

Application::~Application() {}
bool Application::init(const int &width, const int &height) {
  mWidth = width;
  mHeight = height;
  // 1 初始化 GLFW 的窗体系统
  glfwInit();
  // 1.1 设置主/次版本号
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
  // 1.2 启用核心模式
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  //   2 创建窗体对象
  mWindow = glfwCreateWindow(mWidth, mHeight, "OpenGLStudy", NULL, NULL);
  if (!mWindow) {
    glfwTerminate();
    return false;
  }
  glfwMakeContextCurrent(mWindow);
  // 使用 glad 加载所有当前版本 opengl 的函数
  if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
    return false;
  }

  glfwSetFramebufferSizeCallback(mWindow, frameBufferSizeCallback);

  // 设置用户指针
  glfwSetWindowUserPointer(mWindow, this);

  // 键盘消息
  glfwSetKeyCallback(mWindow, keyCallback);

  // 键盘响应
  return true;
}

bool Application::update() {
  if (glfwWindowShouldClose(mWindow)) {
    return false;
  }

  //   接收并分发窗体消息
  //   检查消息队列是否有需要处理的鼠标、键盘消息。如果有的话则批量处理并清空队列
  glfwPollEvents();

  // 切换双缓存
  glfwSwapBuffers(mWindow);
  return true;
}

void Application::destroy() {
  //   退出程序前做相关清理
  glfwTerminate();
}
